#pragma once

#include <vector>
#include <queue>
#include "Thread.h"
#include "Log.h"
#include "Cond.h"
#include "Mutex.h"

namespace zmh
{
    template <class T>
    class ThreadPool
    {
        ThreadPool(size_t cnt)
            : _tp(cnt), _isrunning(false) {}

        static ThreadPool<T> *ptr;
        static Mutex lock;

    public:
        // 以懒汉的方式实现线程安全的单例模式
        static ThreadPool<T> *GetHandler(size_t cnt)
        {
            // 我要返回一个对象,但是用户无法实例化一个(哪怕是空)的对象
            // 1. 需要提供静态的全局变量指针ThreadPool<T> 2. 返回值只能是指针
            // 我要确保多线程同时调用的时候,是线程安全的
            // 但多个线程每次调用都要申请锁,效率太低了,其次真正需要互斥资源的情况是第一次调用

            if (ptr)
                return ptr;

            auto_Mutex guard_mutex(lock);
            if (ptr == nullptr)
            {
                ptr = new ThreadPool<T>(cnt);
                if (ptr == nullptr)
                    LOG(WARNING) << "线程池对象实例化失败...";
                else
                    LOG(INFO) << "已完成线程池对象的实例化...";
                return ptr;
            }
            else
                return ptr;
        }

        ~ThreadPool()
        {
            if (_isrunning == true)
            {
                LOG(FATAL) << "用户没有对线程资源进行手动回收,现终止进程...";
                Stop();
                exit(-1);
            }
            else
                LOG(INFO) << "线程池信息销毁...";
        }
        void Start()
        {
            if (_isrunning == false)
            {
                LOG(INFO) << "开始创建线程...";
                _isrunning = true;
                for (auto &ptr : _tp)
                {
                    ptr = new Thread(&ThreadPool<T>::Dequeue, this);
                    if (ptr == nullptr)
                        LOG(zmh::ERROR) << "线程创建失败...";
                    else
                        LOG(zmh::INFO) << ptr->get_id() << "线程创建成功...";
                }
            }
            else
                LOG(WARNING) << "线程池已是运行中...";
        }
        void Stop()
        {
            // step1 --- 线程池状态修改
            _isrunning = false;
            // step2 --- 不允许有线程 等待唤醒
            _cond.broadcast();
            // step3 --- 线程已全部退出 进行join
            for (auto &ptr : _tp)
            {
                ptr->join();
                delete ptr;
            }
        }
        void Dequeue()
        {
            while (true)
            {
                T task;
                {
                    auto_Mutex guard_mutex(_mutex);
                    while (_qu.empty() && _isrunning) // 线程状态由运行->等待唤醒的必要条件:队列为空、进程池状态为true
                    {
                        _cond.wait(_mutex);
                    }
                    if (_qu.empty() && !_isrunning)
                    {
                        LOG(zmh::INFO) << pthread_self() << "线程已退出...";
                        break;
                    }
                    task = _qu.front();
                    _qu.pop();
                }
                LOG(zmh::INFO) << pthread_self() << "线程处理了一个任务...";
                task();
            }
        }
        void Enqueue(T task)
        {
            if (_isrunning == false)
                return;

            auto_Mutex guard_mutex(_mutex);
            _qu.emplace(task);
            _cond.signal();
        }

    private:
        std::vector<Thread *> _tp; // 对线程类的组织
        std::queue<T> _qu;         // 交易场所使用的适配器
        bool _isrunning;           // 该线程池是否正在运行
        Mutex _mutex;              // 互斥锁
        Cond _cond;                // 条件变量
    };
    template <class T>
    ThreadPool<T> *ThreadPool<T>::ptr = nullptr;
    template <class T>
    Mutex ThreadPool<T>::lock;
}